@file:Suppress("UNCHECKED_CAST")

package cn.com.miao.lynx.common.core.util

import cn.hutool.core.util.ReflectUtil
import net.sf.cglib.beans.BeanCopier
import net.sf.cglib.beans.BeanGenerator
import net.sf.cglib.beans.BeanMap
import java.lang.reflect.Field
import java.lang.reflect.InvocationTargetException
import java.util.*

/**
 * CglibUtil
 * @title: CglibUtil
 * @description:
 * @author: dengmiao
 * @create: 2019-12-20 17:14
 */
object CglibUtil {

    /**
     * cglib生产目标类的子类
     * @param propertyMap{String, Class} 属性类型map
     * @param valueMap{String, Object} 属性值map
     * @param clazz 父类模板
     * @param <T>
     * @return
    </T> */
    @JvmStatic
    fun <T> generate(propertyMap: Map<String?, Any?>, valueMap: Map<String?, Any?>?, clazz: Class<T>?): T {
        val generator = BeanGenerator()
        val propertyIterator = propertyMap.entries.iterator()
        while (propertyIterator.hasNext()) {
            val next = propertyIterator.next()
            generator.addProperty(next.key, next.value as Class<*>?)
        }
        generator.setSuperclass(clazz)
        val t = generator.create() as T
        val beanMap = BeanMap.create(t)
        beanMap.putAll(valueMap!!)
        return t
    }

    @Throws(ClassNotFoundException::class, InvocationTargetException::class, IllegalAccessException::class)
    @JvmStatic
    fun main(args: Array<String>) {
        val generate = generate(object : HashMap<String?, Class<*>?>(1) {
            init {
                put("age", Class.forName("java.lang.Integer"))
            }
        },
                object : HashMap<String?, Any?>(1) {
                    init {
                        put("age", 25)
                    }
                },
                User::class.java)
        val build = User()
        build.id = 1
        BeanCopier.create(User::class.java, generate.javaClass, false).copy(build, generate, null)
        val clazz: Class<*> = generate.javaClass
        Arrays.stream(ReflectUtil.getFieldsDirectly(clazz, true)).forEach { x: Field? -> println(x) }
        val methods = ReflectUtil.getMethodsDirectly(clazz, true)
        for (i in methods.indices) {
            val m = methods[i]
            val modifiers = m.modifiers
            val length = m.parameters.size
            if (modifiers == 1 && length == 0 && m.returnType.name != "void") {
                println(m.name + ": " + m.invoke(generate))
            }
        }
        val target = User()
        target.name = "张三"
        BeanCopier.create(User::class.java, User::class.java, false).copy(target, build, null)
        println(build)
    }
}

open class User {
    var id: Int? = null
    var name: String? = null
}
